
package com.sskj.wechat.service.impl;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.sskj.common.tree.TreeNode;
import com.sskj.common.tree.TreeUtil;
import com.sskj.common.util.Assert;
import com.sskj.core.annotation.ControllerLogExeTime;
import com.sskj.core.util.JsonUtil;
import com.sskj.core.util.TableToExcelUtil;
import com.sskj.wechat.domain.WeChatMenuJQTreeNode;
import com.sskj.wechat.domain.WeChatMenuQueryParam;
import com.sskj.wechat.domain.entity.WeChatMenuEntity;
import com.sskj.wechat.repository.WeChatMenuRepository;

import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.menu.WxMenu;
import me.chanjar.weixin.common.bean.menu.WxMenuButton;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpMenuService;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult;
import me.chanjar.weixin.mp.bean.menu.WxMpMenu;

@Transactional
@RestController
@RequestMapping(value = "/wechat", method = { RequestMethod.POST, RequestMethod.GET })
public class WeChatMenuServiceImpl implements WxMpMenuService {

	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	@Autowired
	WeChatMenuRepository weChatMenuRepository;

	@Autowired
	private WxMpService wxService;

	/**
	 * <pre>
	 * 自定义菜单创建接口
	 * 详情请见：https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN
	 * 如果要创建个性化菜单，请设置matchrule属性
	 * 详情请见：https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
	 * </pre>
	 *
	 * @param menu
	 * @return 如果是个性化菜单，则返回menuid，否则返回null
	 */
	@Override
	@PostMapping("/create")
	public String menuCreate(@RequestBody WxMenu menu) throws WxErrorException {

		return this.wxService.getMenuService().menuCreate(menu);
	}

	@SuppressWarnings({ "rawtypes" })
	private void iteratorWeChat(List<? extends TreeNode> list, List<WxMenuButton> result) {

		if (list != null && !list.isEmpty()) {

			for (TreeNode tree : list) {
				String id = tree.getId();

				WeChatMenuEntity obj = weChatMenuRepository.get(id);

				WxMenuButton wmbt = new WxMenuButton();

				wmbt.setKey(obj.getLableKey());
				wmbt.setType(obj.getType());
				wmbt.setName(obj.getName());
				wmbt.setUrl(obj.getUrl());

				for (Object ctree : tree.getChildren()) {
					String cid = ((TreeNode) ctree).getId();
					WeChatMenuEntity cobj = weChatMenuRepository.get(cid);
					WxMenuButton cwmbt = new WxMenuButton();
					cwmbt.setKey(cobj.getLableKey());
					cwmbt.setType(cobj.getType());
					cwmbt.setName(cobj.getName());
					cwmbt.setUrl(wxService.oauth2buildAuthorizationUrl(cobj.getUrl(), WxConsts.OAUTH2_SCOPE_USER_INFO,
							null));

					wmbt.getSubButtons().add(cwmbt);
				}

				result.add(wmbt);
			}
		}
	}

	@SuppressWarnings({ "rawtypes" })
	@RequestMapping("/menu/create")
	public void menuCreateSample() throws WxErrorException {
		this.logger.info("\n 开始创建菜单...");

		this.menuDelete();
		List<WeChatMenuEntity> list = this.weChatMenuRepository.findAllWeChatMenu();
		List<WxMenuButton> result = new ArrayList<WxMenuButton>();
		List<TreeNode> treeList = TreeUtil.build(list);
		iteratorWeChat(treeList, result);
		WxMenu menu = new WxMenu();
		menu.getButtons().addAll(result);

		System.out.println(this.menuCreate(menu));

	}

	@RequestMapping({ "**/menu/page" })
	@ControllerLogExeTime(description = "查询微信公众号菜单资源", log = false)
	public Page<WeChatMenuJQTreeNode> queryPage(WeChatMenuQueryParam weChatMenuQueryParam, Pageable pageable) {
		List<WeChatMenuEntity> list = this.weChatMenuRepository.findAllWeChatMenu();
		List<WeChatMenuJQTreeNode> nodes = buildJQTreeNode(list);
		Page<WeChatMenuJQTreeNode> page = new PageImpl<WeChatMenuJQTreeNode>(nodes);

		System.out.println(JsonUtil.json(nodes));

		return page;
	}

	@RequestMapping(value = "**/menu/save", method = { RequestMethod.POST, RequestMethod.PUT })
	@ControllerLogExeTime(description = "新增微信公众号菜单资源")
	public WeChatMenuEntity save(WeChatMenuEntity weChatMenuEntity) {
		String parentId = weChatMenuEntity.getParentId();
		if (StringUtils.isNotEmpty(parentId)) {
			WeChatMenuEntity parent = weChatMenuRepository.get(parentId);
			if (parent == null) {
				Assert.throwException("sys.recource.parentNot");
			}
		}
		weChatMenuRepository.save(weChatMenuEntity);
		return weChatMenuEntity;
	}

	@RequestMapping(value = "**/menu/update", method = { RequestMethod.POST, RequestMethod.PUT })
	@ControllerLogExeTime(description = "修改微信公众号菜单资源")
	public void update(WeChatMenuEntity weChatMenuEntity) {
		String id = weChatMenuEntity.getId();
		WeChatMenuEntity entity = weChatMenuRepository.get(id);
		entity.setType(weChatMenuEntity.getType());
		entity.setLableKey(weChatMenuEntity.getLableKey());
		entity.setName(weChatMenuEntity.getName());
		entity.setSortNum(weChatMenuEntity.getSortNum());
		entity.setUrl(weChatMenuEntity.getUrl());
		weChatMenuRepository.save(entity);
	}

	@ControllerLogExeTime(description = "删除微信公众号菜单资源")
	@RequestMapping({ "**/menu/del" })
	public void del(String id) {
		if (StringUtils.isNotEmpty(id)) {
			WeChatMenuEntity entity = this.get(id);
			cascadeDelete(entity);
		}
	}

	@ControllerLogExeTime(description = "获取微信公众号菜单资源", log = false)
	@RequestMapping({ "**/menu/get" })
	public WeChatMenuEntity get(String id) {
		WeChatMenuEntity weChatMenuEntity = weChatMenuRepository.get(id);
		return weChatMenuEntity;
	}

	@ControllerLogExeTime(description = "查看微信公众号菜单资源", log = false)
	@RequestMapping({ "**/menu/detail" })
	public WeChatMenuEntity detail(String id) {
		WeChatMenuEntity weChatMenuEntity = weChatMenuRepository.get(id);
		return weChatMenuEntity;
	}

	@RequestMapping(value = { "**/menu/excel" }, method = { RequestMethod.POST })
	@ControllerLogExeTime(description = "导出微信公众号菜单资源", log = false)
	public void excel(String html, HttpServletResponse response) throws IOException {
		response.setContentType("application/msexcel;charset=UTF-8");
		response.addHeader("Content-Disposition", "attachment;filename=resources.xls");
		OutputStream out = response.getOutputStream();
		TableToExcelUtil.createExcelFormTable("timedTask", html, 1, out);
		out.flush();
		out.close();
	}

	@SuppressWarnings("rawtypes")
	private List<WeChatMenuJQTreeNode> buildJQTreeNode(List<WeChatMenuEntity> list) {

		List<WeChatMenuJQTreeNode> nodes = null;
		if (list != null) {
			nodes = new ArrayList<WeChatMenuJQTreeNode>();
			Map<String, WeChatMenuJQTreeNode> map = new HashMap<String, WeChatMenuJQTreeNode>();
			for (WeChatMenuEntity entity : list) {
				WeChatMenuJQTreeNode node = new WeChatMenuJQTreeNode();
				String parentId = entity.getParentId();
				node.setId(entity.getId());
				node.setParentId(parentId);
				node.setParent(parentId);
				node.setName(entity.getName());
				node.setUrl(entity.getUrl());
				node.setSortNum(entity.getSortNum());
				node.setLableKey(entity.getLableKey());
				node.setType(entity.getType());
				node.setIsLeaf(true);

				map.put(node.getId(), node);
				nodes.add(node);
			}
			Collection<WeChatMenuJQTreeNode> values = map.values();
			for (WeChatMenuJQTreeNode node : values) {
				String parentId = node.getParentId();
				String tempParentId = parentId;
				int level = 0;
				while (StringUtils.isNotEmpty(tempParentId)) {
					WeChatMenuJQTreeNode temp = map.get(tempParentId);
					temp.setIsLeaf(false);
					if (temp != null) {
						level++;
						tempParentId = temp.getParentId();
					}
				}
				node.setLevel(level);
			}

			List<TreeNode> treeList = TreeUtil.build(list);
			List<WeChatMenuJQTreeNode> result = new ArrayList<WeChatMenuJQTreeNode>();
			iterator(treeList, result, map);
			return result;

		}
		return null;
	}

	@SuppressWarnings({ "rawtypes" })
	private void iterator(List<? extends TreeNode> list, List<WeChatMenuJQTreeNode> result,
			Map<String, WeChatMenuJQTreeNode> map) {

		if (list != null && !list.isEmpty()) {
			for (TreeNode tree : list) {
				String id = tree.getId();
				WeChatMenuJQTreeNode weChatMenuJQTreeNode = map.get(id);
				result.add(weChatMenuJQTreeNode);
				@SuppressWarnings("unchecked")
				List<TreeNode> children = tree.getChildren();
				if (children != null && !list.isEmpty()) {
					iterator(children, result, map);
				}
			}
		}
	}

	private void cascadeDelete(WeChatMenuEntity entity) {
		if (entity != null) {
			weChatMenuRepository.delete(entity);
			List<WeChatMenuEntity> children = weChatMenuRepository.findWeChatMenuByParentId(entity.getId());
			if (children != null && !children.isEmpty()) {
				for (WeChatMenuEntity child : children) {
					cascadeDelete(child);
				}
			}
		}
	}

	/**
	 * <pre>
	 * 自定义菜单删除接口
	 * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141015&token=&lang=zh_CN
	 * </pre>
	 */
	@Override
	public void menuDelete() throws WxErrorException {
		this.wxService.getMenuService().menuDelete();
	}

	/**
	 * <pre>
	 * 删除个性化菜单接口
	 * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
	 * </pre>
	 *
	 * @param menuId
	 *            个性化菜单的menuid
	 */
	@Override
	public void menuDelete(@PathVariable String menuId) throws WxErrorException {

		this.wxService.getMenuService().menuDelete(menuId);
	}

	/**
	 * <pre>
	 * 自定义菜单查询接口
	 * 详情请见： https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141014&token=&lang=zh_CN
	 * </pre>
	 */
	@Override
	public WxMpMenu menuGet() throws WxErrorException {
		return this.wxService.getMenuService().menuGet();
	}

	/**
	 * <pre>
	 * 测试个性化菜单匹配结果
	 * 详情请见: http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
	 * </pre>
	 *
	 * @param userid
	 *            可以是粉丝的OpenID，也可以是粉丝的微信号。
	 */
	@Override
	public WxMenu menuTryMatch(@PathVariable String userid) throws WxErrorException {
		return this.wxService.getMenuService().menuTryMatch(userid);
	}

	/**
	 * <pre>
	 * 获取自定义菜单配置接口
	 * 本接口将会提供公众号当前使用的自定义菜单的配置，如果公众号是通过API调用设置的菜单，则返回菜单的开发配置，而如果公众号是在公众平台官网通过网站功能发布菜单，则本接口返回运营者设置的菜单配置。
	 * 请注意：
	 * 1、第三方平台开发者可以通过本接口，在旗下公众号将业务授权给你后，立即通过本接口检测公众号的自定义菜单配置，并通过接口再次给公众号设置好自动回复规则，以提升公众号运营者的业务体验。
	 * 2、本接口与自定义菜单查询接口的不同之处在于，本接口无论公众号的接口是如何设置的，都能查询到接口，而自定义菜单查询接口则仅能查询到使用API设置的菜单配置。
	 * 3、认证/未认证的服务号/订阅号，以及接口测试号，均拥有该接口权限。
	 * 4、从第三方平台的公众号登录授权机制上来说，该接口从属于消息与菜单权限集。
	 * 5、本接口中返回的图片/语音/视频为临时素材（临时素材每次获取都不同，3天内有效，通过素材管理-获取临时素材接口来获取这些素材），本接口返回的图文消息为永久素材素材（通过素材管理-获取永久素材接口来获取这些素材）。
	 *  接口调用请求说明:
	 * http请求方式: GET（请使用https协议）
	 * https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=ACCESS_TOKEN
	 * </pre>
	 */
	@Override
	public WxMpGetSelfMenuInfoResult getSelfMenuInfo() throws WxErrorException {
		return this.wxService.getMenuService().getSelfMenuInfo();
	}

	/**
	 * <pre>
	 * 自定义菜单创建接口
	 * 详情请见： https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN
	 * 如果要创建个性化菜单，请设置matchrule属性
	 * 详情请见：https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
	 * </pre>
	 *
	 * @param json
	 * @return 如果是个性化菜单，则返回menuid，否则返回null
	 */
	@Override
	public String menuCreate(@PathVariable String json) throws WxErrorException {
		return this.wxService.getMenuService().menuCreate(json);
	}

}
